package com.doumuxie.service.impl;

import com.doumuxie.common.dto.UserDto;
import com.doumuxie.common.entity.User;
import com.doumuxie.exception.RunErrorException;
import com.doumuxie.repository.UserRepository;
import com.doumuxie.service.UserLoginLogService;
import com.doumuxie.service.UserService;
import com.doumuxie.util.Md5Util;
import com.doumuxie.util.ResultUtil;
import com.doumuxie.util.SysCode;
import com.doumuxie.util.UUIDUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @author doumuxie https://gitee.com/doumuxie/
 * @version 1.0
 * @date 2020/11/30 19:06
 * @description 业务层 实现
 **/
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    final UserRepository userRepository;

    final UserLoginLogService userLoginLogService;
    /**
     * 模拟redis存储用户登录token信息
     * 当前不设置过期时间
     */
    public static Map<String, String> TOKEN_USER_ID_MAP;

    static {
        TOKEN_USER_ID_MAP = new HashMap<>();
    }


    @Override
    public ResultUtil userInfo(String token) {
        if (StringUtils.isBlank(token)) {
            return ResultUtil.paramError();
        }
        String userId = TOKEN_USER_ID_MAP.get(token);
        if (userId == null) {
            throw new RunErrorException("无效token");
        }
        User one = userRepository.getOne(userId);
        HashMap<String, String> result = new HashMap<>();
        result.put("id", one.getId());
        result.put("username", one.getUsername());
        return ResultUtil.success(result);
    }

    @Override
    public ResultUtil regUser(UserDto dto) {
        // 用户名密码校验
        if (StringUtils.isAnyBlank(dto.getUsername(), dto.getPassword())) {
            return ResultUtil.paramError();
        }
        // 邮箱手机必须其一校验
        if (StringUtils.isAllBlank(dto.getCellphone(), dto.getEmail())) {
            return ResultUtil.paramError();
        }
        // TODO 不进行验证码校验
        // 用户名去重校验
        User temp = new User();
        temp.setUsername(dto.getUsername());
        long count = getSameCount(temp);
        if (count > 0) {
            throw new RunErrorException("用户名已存在");
        }
        // 邮箱 / 手机号去重校验
        if (StringUtils.isNotBlank(dto.getCellphone())) {
            temp = new User();
            temp.setCellphone(dto.getCellphone());
            count = getSameCount(temp);
            if (count > 0) {
                throw new RunErrorException("手机号已被使用");
            }
        } else if (StringUtils.isNotBlank(dto.getEmail())) {
            temp = new User();
            temp.setEmail(dto.getEmail());
            count = getSameCount(temp);
            if (count > 0) {
                throw new RunErrorException("邮箱已被使用");
            }
        }
        // 生成盐值
        String salt = UUIDUtil.getRandomId();
        String password;
        try {
            password = Md5Util.getMD5Code(dto.getPassword() + salt);
        } catch (Exception exception) {
            return ResultUtil.serverBusy();
        }
        User user = new User();
        user.setUsername(dto.getUsername());
        user.setPassword(password);
        user.setEmail(dto.getEmail());
        user.setCellphone(dto.getCellphone());
        user.setSalt(salt);
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        user.setState(SysCode.UserState.OK);
        User res = userRepository.save(user);
        if (StringUtils.isBlank(res.getId())) {
            throw new RunErrorException("注册失败");
        }
        return ResultUtil.success();
    }

    @Override
    public ResultUtil login(UserDto dto, String ipAddress) {
        // 用户名密码校验 不使用手机号 / 邮箱 登录
        if (StringUtils.isAnyBlank(dto.getUsername(), dto.getPassword())) {
            return ResultUtil.paramError();
        }
        // 根据用户名查询用户
        Optional<User> userOptional = userRepository.findOne(new Example<User>() {
            @Override
            public User getProbe() {
                User user = new User();
                user.setUsername(dto.getUsername());
                return user;
            }

            @Override
            public ExampleMatcher getMatcher() {
                return ExampleMatcher.matching();
            }
        });
        if (!userOptional.isPresent()) {
            // 查询不存在
            throw new RunErrorException("用户名或密码错误");
        }
        User user = userOptional.get();
        String md5Password = null;
        try {
            md5Password = Md5Util.getMD5Code(dto.getPassword() + user.getSalt());
        } catch (Exception exception) {
            throw new RunErrorException(SysCode.SERVER_BUSY);
        }
        if (!md5Password.equals(user.getPassword())) {
            // 密码错误
            throw new RunErrorException("用户名或密码错误");
        }
        // 保存日志
        userLoginLogService.save(user.getId(), ipAddress);
        // 记录登录状态 可同时在线
        String token = UUIDUtil.getRandomId();
        TOKEN_USER_ID_MAP.put(token, user.getId());
        // 返回token
        return ResultUtil.success(token);
    }

    /**
     * 获取符合条件的用户的数量
     *
     * @param user 条件
     * @return count
     */
    private long getSameCount(User user) {
        return userRepository.count(new Example<User>() {
            @Override
            public User getProbe() {
                return user;
            }

            @Override
            public ExampleMatcher getMatcher() {
                return ExampleMatcher.matching();
            }
        });
    }
}
